home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / HIERSV.PAK / SVRITEM.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  21KB  |  838 lines

  1. // svrnode.cpp : implementation of the CServerNode class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13.  
  14. #include "stdafx.h"
  15. #include <afxpriv.h>    // for CSharedFile
  16. #include <malloc.h>     // for _alloca
  17.  
  18. #include "hiersvr.h"
  19. #include "svritem.h"
  20. #include "svrdoc.h"
  21. #include "svrview.h"
  22.  
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // Local dialogs used for implementation
  30.  
  31. class CChangeNameDlg : public CDialog
  32. {
  33. // Construction
  34. public:
  35.     CChangeNameDlg(CWnd* pParent = NULL);
  36.  
  37. // Dialog Data
  38.     //{{AFX_DATA(CChangeNameDlg)
  39.     enum { IDD = IDD_CHANGE_NAME };
  40.     int     m_shape;
  41.     CString m_strDescription;
  42.     CString m_strLinkKey;
  43.     CEdit   m_editDescription;
  44.     CButton m_btnOK;
  45.     //}}AFX_DATA
  46.  
  47. // Implementation
  48. protected:
  49.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  50.     virtual BOOL OnInitDialog();
  51.     // Generated message map functions
  52.     //{{AFX_MSG(CChangeNameDlg)
  53.     afx_msg void OnChange();
  54.     //}}AFX_MSG
  55.     DECLARE_MESSAGE_MAP()
  56. };
  57.  
  58. class CAddNodeDlg : public CDialog
  59. {
  60. // Construction
  61. public:
  62.     CAddNodeDlg(CWnd* pParent = NULL);  // standard constructor
  63.  
  64. // Dialog Data
  65.     //{{AFX_DATA(CAddNodeDlg)
  66.     enum { IDD = IDD_ADD_NODE };
  67.     CString m_strDescription;
  68.     CString m_strLinkKey;
  69.     int     m_shape;
  70.     CEdit   m_editDescription;
  71.     CButton m_btnOK;
  72.     //}}AFX_DATA
  73.  
  74. // Implementation
  75. protected:
  76.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  77.     virtual BOOL OnInitDialog();
  78.  
  79.     // Generated message map functions
  80.     //{{AFX_MSG(CAddNodeDlg)
  81.     afx_msg void OnChange();
  82.     //}}AFX_MSG
  83.     DECLARE_MESSAGE_MAP()
  84. };
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CServerNode
  88.  
  89. IMPLEMENT_SERIAL(CServerNode, CObject, 0);
  90.  
  91. CServerNode::CServerNode(CServerDoc* pServerDoc)
  92. {
  93.     m_shape = shapeRect;
  94.     m_bHideChildren = FALSE;
  95.     m_pDocument = pServerDoc;
  96.  
  97.     m_pServerItem = NULL;   // will get connected if need be
  98. }
  99.  
  100. // Special "new" operator for root node
  101. CServerNode* CServerNode::CreateRootNode(CServerDoc* pDoc)
  102. {
  103.     CServerNode* pRoot = NULL;
  104.     TRY
  105.     {
  106.         pRoot = new CServerNode(pDoc);
  107.         pRoot->InitRootNode();
  108.     }
  109.     CATCH(CException, e)
  110.     {
  111.         delete pRoot;
  112.         pRoot = NULL;
  113.     }
  114.     END_CATCH
  115.  
  116.     return pRoot;
  117. }
  118.  
  119. // Special constructor for root node
  120. void CServerNode::InitRootNode()
  121. {
  122.     DeleteChildNodes(); // initalized root node has no children
  123.  
  124.     m_strDescription = "Root node";
  125.     m_strLinkKey = "%ROOT%";    // link name for root
  126.     UpdateItemName();
  127. }
  128.  
  129. BOOL CServerNode::FindAndDelete(CServerNode* pNode)
  130. {
  131.     POSITION pos = m_listChild.GetHeadPosition();
  132.     while (pos != NULL)
  133.     {
  134.         POSITION posPrev = pos;
  135.         CServerNode *pChild = (CServerNode*)m_listChild.GetNext(pos);
  136.         if (pChild == pNode)
  137.         {
  138.             m_listChild.RemoveAt(posPrev);
  139.             delete pNode;
  140.             return TRUE;
  141.         }
  142.         if (pChild->FindAndDelete(pNode) == TRUE)
  143.             return TRUE;
  144.     }
  145.     return FALSE;
  146. }
  147.  
  148. CServerNode* CServerNode::FindNode(LPCTSTR pszItemName)
  149. {
  150.     // return this node if it matches!
  151.     if (GetItemName() == pszItemName)
  152.         return this;
  153.  
  154.     POSITION pos = m_listChild.GetHeadPosition();
  155.     while (pos != NULL)
  156.     {
  157.         CServerNode* pChild = (CServerNode*)m_listChild.GetNext(pos);
  158.         if (pChild->GetItemName() == pszItemName)
  159.             return pChild;
  160.  
  161.         // recurse down the tree
  162.         pChild = pChild->FindNode(pszItemName);
  163.         if (pChild != NULL)
  164.             return pChild;
  165.     }
  166.     return NULL;
  167. }
  168.  
  169. void CServerNode::DeleteChildNodes()
  170. {
  171.     // delete child nodes
  172.     POSITION pos = m_listChild.GetHeadPosition();
  173.     while (pos != NULL)
  174.         delete m_listChild.GetNext(pos);
  175.     m_listChild.RemoveAll();
  176. }
  177.  
  178. CServerNode::~CServerNode()
  179. {
  180.     // if we are the root of a document, clear it
  181.     if (GetDocument()->m_pRoot == this)
  182.         GetDocument()->m_pRoot = NULL;
  183.  
  184.     // if we are attached to a server item, detach from it
  185.     if (m_pServerItem != NULL)
  186.     {
  187.         CServerItem* pItem = m_pServerItem;
  188.         m_pServerItem = NULL;
  189.         delete pItem;
  190.     }
  191.  
  192.     // delete all of the child nodes of this node
  193.     DeleteChildNodes();
  194. }
  195.  
  196. BOOL CServerNode::IsChild(const CServerNode* pPotentialChild) const
  197. {
  198.     if (pPotentialChild == this)
  199.         return TRUE;
  200.     POSITION pos = m_listChild.GetHeadPosition();
  201.     while (pos != NULL)
  202.     {
  203.         CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  204.         if (pNode->IsChild(pPotentialChild))
  205.             return TRUE;
  206.     }
  207.     return FALSE;
  208. }
  209.  
  210. /////////////////////////////////////////////////////////////////////////////
  211. // CServerNode bounding rect helpers
  212.  
  213. #define CX_INSET    4
  214. #define CY_INSET    2
  215.  
  216. // calc node size for arbitrary dc and return
  217. //  (result is in logical units for the given DC)
  218. void CServerNode::CalcNodeSize(CDC* pDC, CSize& sizeNode)
  219. {
  220.     ASSERT(pDC != NULL);
  221.     sizeNode = pDC->GetTextExtent(m_strDescription,
  222.         m_strDescription.GetLength());
  223.     sizeNode += CSize(CX_INSET * 2, CY_INSET * 2);
  224. }
  225.  
  226. // calculate bounding rect using pointer to member for each node
  227. void CServerNode::CalcBounding(CDC* pDC, CPoint& ptStart, CSize& sizeMax)
  228. {
  229.     ASSERT(sizeMax.cx >= 0 && sizeMax.cy >= 0);
  230.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  231.  
  232.     CSize sizeNode;
  233.     CalcNodeSize(pDC, sizeNode);
  234.  
  235.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  236.     if (ptStart.y > sizeMax.cy)
  237.         sizeMax.cy = ptStart.y;
  238.  
  239.     if (ptStart.x + sizeNode.cx > sizeMax.cx)
  240.         sizeMax.cx = ptStart.x + sizeNode.cx;
  241.     ptStart.x += CX_INDENT;
  242.     // add in the kids
  243.     if (!m_bHideChildren)
  244.     {
  245.         POSITION pos = m_listChild.GetHeadPosition();
  246.         while (pos != NULL)
  247.         {
  248.             CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  249.             pNode->CalcBounding(pDC, ptStart, sizeMax);
  250.         }
  251.     }
  252.     ptStart.x -= CX_INDENT;
  253. }
  254.  
  255. /////////////////////////////////////////////////////////////////////////////
  256. // CServerNode drawing helpers
  257.  
  258. BOOL CServerNode::Draw(CDC* pDC, CPoint pt, BOOL bSelected, CSize sizeNode)
  259. {
  260.     CRect rect(pt, sizeNode);
  261.     if (!pDC->RectVisible(&rect))
  262.         return TRUE;
  263.  
  264.     // draw a the bounding shape
  265.     BOOL bOK = TRUE;
  266.  
  267.     CPen* pOldPen = NULL;
  268.     CPen penHilite;
  269.     int nPenStyle = (m_bHideChildren) ? PS_DASH : PS_SOLID;
  270.     COLORREF crPen = (bSelected) ? RGB(255,0,0) : RGB(0,0,0);
  271.     if (penHilite.CreatePen(nPenStyle, 0, crPen))
  272.         pOldPen = pDC->SelectObject(&penHilite);
  273.  
  274.     switch (m_shape)
  275.     {
  276.     case shapeRect:
  277.         bOK = pDC->Rectangle(rect);
  278.         break;
  279.     case shapeRound:
  280.         bOK = pDC->RoundRect(rect, CPoint(7, 7));
  281.         break;
  282.     case shapeOval: // really just a rounder rounded rect
  283.         bOK = pDC->RoundRect(rect, CPoint(14, 14));
  284.         break;
  285.     default:
  286.         TRACE1("Error: unknown shape %d\n", m_shape);
  287.         bOK = FALSE;
  288.         break;
  289.     }
  290.     if (pOldPen != NULL)
  291.         pDC->SelectObject(pOldPen);
  292.  
  293.     if (!bOK)
  294.         return FALSE;
  295.  
  296.     // inset a bit
  297.     rect.InflateRect(-CX_INSET, -CY_INSET);
  298.  
  299.     if (!pDC->ExtTextOut(rect.left, rect.top, ETO_OPAQUE, rect,
  300.       m_strDescription, m_strDescription.GetLength(), NULL))
  301.         return FALSE;
  302.  
  303.     // all OK
  304.     return TRUE;
  305. }
  306.  
  307. int CServerNode::DrawTree(CDC* pDC, CPoint ptStart, CServerNode* pNodeSel)
  308. {
  309.     ASSERT(pDC != NULL);
  310.     ASSERT(ptStart.x >= 0 && ptStart.y >= 0);
  311.  
  312.     // root node starts here
  313.     int cyDrawn = 0;
  314.     CSize sizeNode;
  315.     CalcNodeSize(pDC, sizeNode);
  316.     Draw(pDC, ptStart, this == pNodeSel, sizeNode);
  317.     cyDrawn += sizeNode.cy + CY_SEPARATOR;
  318.  
  319.     if (m_listChild.GetCount() == 0 || m_bHideChildren)
  320.         return cyDrawn;     // nothing more to draw
  321.  
  322.     // indent for the kids
  323.     CPoint ptKid(ptStart.x + CX_INDENT, ptStart.y + cyDrawn);
  324.  
  325.     // draw the kids
  326.     int yMid = 0;
  327.     POSITION pos = m_listChild.GetHeadPosition();
  328.     while (pos != NULL)
  329.     {
  330.         CServerNode *pChild = (CServerNode*)m_listChild.GetNext(pos);
  331.  
  332.         // add the little line
  333.         yMid = ptKid.y + (sizeNode.cy)/2;
  334.         pDC->MoveTo(ptStart.x + CX_BACKDENT, yMid);
  335.         pDC->LineTo(ptKid.x, yMid);
  336.  
  337.         // draw the child node
  338.         int cyKid = pChild->DrawTree(pDC, ptKid, pNodeSel);
  339.         if (cyKid == -1)
  340.             return -1;      // error
  341.  
  342.         cyDrawn += cyKid;
  343.         ptKid.y += cyKid;
  344.     }
  345.     ASSERT(ptKid.y == ptStart.y + cyDrawn);
  346.  
  347.     // draw the connecting line (down to last yMid)
  348.     ASSERT(yMid != 0);
  349.     int xLine = ptStart.x + CX_BACKDENT;
  350.     pDC->MoveTo(xLine, ptStart.y + sizeNode.cy);
  351.     pDC->LineTo(xLine, yMid);
  352.     return cyDrawn;
  353. }
  354.  
  355. // Serializes to file or to embedded OLE stream
  356. void CServerNode::Serialize(CArchive& ar)
  357. {
  358.     CObject::Serialize(ar);
  359.     if (ar.IsStoring())
  360.     {
  361.         ar << (WORD)m_shape;
  362.  
  363.         ASSERT(m_strLinkKey.IsEmpty() || m_strDescription != m_strLinkKey);
  364.         if (m_pServerItem != NULL)
  365.             ar << m_pServerItem->GetItemName();
  366.         else
  367.             ar << m_strLinkKey;
  368.         ar << m_strDescription;
  369.         ar << (WORD)m_bHideChildren;
  370.     }
  371.     else
  372.     {
  373.         // get back-pointer to document
  374.         m_pDocument = (CServerDoc*)ar.m_pDocument;
  375.  
  376.         WORD wTemp;
  377.         ar >> wTemp; m_shape = (EShape)wTemp;
  378.         if (m_shape >= shapeMax)
  379.             m_shape = shapeRect;
  380.         ar >> m_strLinkKey >> m_strDescription;
  381.         UpdateItemName();
  382.         ar >> wTemp;
  383.         m_bHideChildren = (BOOL)wTemp;
  384.     }
  385.     m_listChild.Serialize(ar);
  386. }
  387.  
  388. /////////////////////////////////////////////////////////////////////////////
  389. // CServerNode support for CF_TEXT format
  390.  
  391. void CServerNode::SaveAsText(CArchive& ar, int nLevel)
  392. {
  393.     ASSERT(ar.IsStoring());
  394.  
  395.     // indent node text
  396.     char szTabs[MAX_LEVEL];
  397.     int nTabs = min(nLevel, MAX_LEVEL);
  398.     memset(szTabs, '\t', nTabs);
  399.     ar.Write(szTabs, nTabs);
  400.  
  401.     // write node text itself
  402. #ifdef _UNICODE
  403.     int nLen = m_strDescription.GetLength();
  404.     char* psz = (char*)_alloca(nLen+1);
  405.     wcstombs(psz, m_strDescription, nLen+1);
  406.     ar.Write(psz, nLen);
  407. #else
  408.     ar.Write(m_strDescription, m_strDescription.GetLength()*sizeof(TCHAR));
  409. #endif
  410.  
  411.     // terminate line with CRLF
  412.     static char BASED_CODE szCRLF[] = "\r\n";
  413.     ar.Write(szCRLF, sizeof(szCRLF)-1);
  414.  
  415.     // write kids
  416.     POSITION pos = m_listChild.GetHeadPosition();
  417.     while (pos != NULL)
  418.     {
  419.         CServerNode* pNode = (CServerNode*)m_listChild.GetNext(pos);
  420.         pNode->SaveAsText(ar, nLevel+1);
  421.     }
  422. }
  423.  
  424. void CServerNode::UpdateItemName()
  425. {
  426.     // empty link key if same as description (it is redundant)
  427.     if (m_strLinkKey == m_strDescription)
  428.         m_strLinkKey.Empty();
  429.  
  430.     // update link name in item if attached
  431.     if (m_pServerItem != NULL)
  432.     {
  433.         CString* pstr;
  434.         if (m_strLinkKey.IsEmpty())
  435.             pstr = &m_strDescription;
  436.         else
  437.             pstr = &m_strLinkKey;
  438.         m_pServerItem->SetItemName(*pstr);
  439.  
  440.         // empty link key since it is redundant with the server item
  441.         m_strLinkKey.Empty();
  442.     }
  443. }
  444.  
  445. const CString& CServerNode::GetItemName()
  446. {
  447.     // use item name in server item if connected
  448.     if (m_pServerItem != NULL)
  449.         return m_pServerItem->GetItemName();
  450.  
  451.     // use description or link key depending on state of link key
  452.     else if (m_strLinkKey.IsEmpty())
  453.         return m_strDescription;
  454.     else
  455.         return m_strLinkKey;
  456. }
  457.  
  458. BOOL CServerNode::PromptChangeNode()
  459. {
  460.     CChangeNameDlg dlg;
  461.     dlg.m_strDescription = m_strDescription;
  462.     dlg.m_strLinkKey = GetItemName();
  463.     if (dlg.m_strLinkKey == dlg.m_strDescription)
  464.         dlg.m_strLinkKey.Empty(); // leave empty for tracking link name
  465.     dlg.m_shape = m_shape;
  466.  
  467.     if (dlg.DoModal() == IDOK)
  468.     {
  469.         m_strDescription = dlg.m_strDescription;
  470.         m_strLinkKey = dlg.m_strLinkKey;
  471.         UpdateItemName();   // syncronize names as appropriate
  472.         m_shape = (EShape)dlg.m_shape;
  473.         return TRUE;
  474.     }
  475.     return FALSE;
  476. }
  477.  
  478. ////////////////////////////////////////////////////////////////
  479. // Creating child nodes
  480.  
  481. // Special constructor for child node
  482. CServerNode* CServerNode::CreateChildNode(LPCTSTR lpszDescription)
  483. {
  484.     CServerNode* pNew = NULL;
  485.     TRY
  486.     {
  487.         pNew = new CServerNode(GetDocument());
  488.         pNew->m_strDescription = lpszDescription;
  489.             // both item name and description start out the same
  490.  
  491.         // add as the last child
  492.         m_listChild.AddTail(pNew);
  493.     }
  494.     CATCH (CException, e)
  495.     {
  496.         delete pNew;
  497.         pNew = NULL;
  498.     }
  499.     END_CATCH
  500.  
  501.     return pNew;
  502. }
  503.  
  504. CServerNode* CServerNode::PromptNewChildNode()
  505. {
  506.     CAddNodeDlg dlg;
  507.     dlg.m_shape = (EShape)shapeRect;
  508.     if (dlg.DoModal() != IDOK)
  509.         return NULL;
  510.  
  511.     CServerNode* pNew = CreateChildNode(dlg.m_strDescription);
  512.     if (pNew == NULL)
  513.         AfxThrowMemoryException();
  514.     pNew->m_shape = (EShape)dlg.m_shape;
  515.     pNew->m_strLinkKey = dlg.m_strLinkKey;
  516.     pNew->UpdateItemName();
  517.  
  518.     return pNew;
  519. }
  520.  
  521. CServerNode* CServerNode::GetNext(CServerNode* pNode, BOOL bInit)
  522. {
  523.     static BOOL bFound;
  524.     if (bInit)
  525.         bFound = FALSE;
  526.  
  527.     if (pNode == this)
  528.         bFound = TRUE;
  529.     if (!m_bHideChildren)
  530.     {
  531.         POSITION pos = m_listChild.GetHeadPosition();
  532.         while (pos != NULL)
  533.         {
  534.             CServerNode* pChild = (CServerNode*)m_listChild.GetNext(pos);
  535.             if (bFound)
  536.                 return pChild;
  537.             pChild = pChild->GetNext(pNode, FALSE);
  538.             if (pChild != NULL)
  539.                 return pChild;
  540.         }
  541.     }
  542.     // if reached top and last level return original
  543.     if (bInit)
  544.         return pNode;
  545.     else
  546.         return NULL;
  547. }
  548.  
  549. CServerNode* CServerNode::GetPrev(CServerNode* pNode,BOOL bInit)
  550. {
  551.     static CServerNode* pPrev;
  552.     if (bInit)
  553.         pPrev = this;
  554.  
  555.     if (pNode == this)
  556.         return pPrev;
  557.  
  558.     pPrev = this;
  559.  
  560.     if (!m_bHideChildren)
  561.     {
  562.         POSITION pos = m_listChild.GetHeadPosition();
  563.         while (pos != NULL)
  564.         {
  565.             CServerNode* pCur = (CServerNode*)m_listChild.GetNext(pos);
  566.             CServerNode* pChild = pCur->GetPrev(pNode, FALSE);
  567.             if (pChild != NULL)
  568.                 return pChild;
  569.         }
  570.     }
  571.     if (bInit)
  572.         return pPrev;
  573.     else
  574.         return NULL;
  575. }
  576.  
  577. /////////////////////////////////////////////////////////////////////////////
  578. // CChangeNameDlg dialog
  579.  
  580. CChangeNameDlg::CChangeNameDlg(CWnd* pParent)
  581.     : CDialog(CChangeNameDlg::IDD, pParent)
  582. {
  583.     //{{AFX_DATA_INIT(CChangeNameDlg)
  584.     //}}AFX_DATA_INIT
  585. }
  586.  
  587. BOOL CChangeNameDlg::OnInitDialog()
  588. {
  589.     CDialog::OnInitDialog();
  590.     OnChange(); // after DDX
  591.     return TRUE;
  592. }
  593.  
  594. void CChangeNameDlg::DoDataExchange(CDataExchange* pDX)
  595. {
  596.     CDialog::DoDataExchange(pDX);
  597.     //{{AFX_DATA_MAP(CChangeNameDlg)
  598.     DDX_CBIndex(pDX, IDC_COMBO1, m_shape);
  599.     DDX_Text(pDX, IDC_EDIT1, m_strDescription);
  600.     DDX_Text(pDX, IDC_EDIT2, m_strLinkKey);
  601.     DDX_Control(pDX, IDC_EDIT1, m_editDescription);
  602.     DDX_Control(pDX, IDOK, m_btnOK);
  603.     //}}AFX_DATA_MAP
  604. }
  605.  
  606. BEGIN_MESSAGE_MAP(CChangeNameDlg, CDialog)
  607.     //{{AFX_MSG_MAP(CChangeNameDlg)
  608.     ON_EN_CHANGE(IDC_EDIT1, OnChange)
  609.     //}}AFX_MSG_MAP
  610. END_MESSAGE_MAP()
  611.  
  612.  
  613. void CChangeNameDlg::OnChange()
  614. {
  615.     if (m_btnOK.m_hWnd)
  616.         m_btnOK.EnableWindow(m_editDescription.GetWindowTextLength() > 0);
  617. }
  618.  
  619. /////////////////////////////////////////////////////////////////////////////
  620. // CAddNodeDlg dialog
  621.  
  622. CAddNodeDlg::CAddNodeDlg(CWnd* pParent /*=NULL*/)
  623.     : CDialog(CAddNodeDlg::IDD, pParent)
  624. {
  625.     //{{AFX_DATA_INIT(CAddNodeDlg)
  626.     //}}AFX_DATA_INIT
  627. }
  628.  
  629. BOOL CAddNodeDlg::OnInitDialog()
  630. {
  631.     CDialog::OnInitDialog();
  632.     OnChange(); // after DDX
  633.     return TRUE;
  634. }
  635.  
  636. void CAddNodeDlg::DoDataExchange(CDataExchange* pDX)
  637. {
  638.     CDialog::DoDataExchange(pDX);
  639.     //{{AFX_DATA_MAP(CAddNodeDlg)
  640.     DDX_Text(pDX, IDC_EDIT1, m_strDescription);
  641.     DDX_Text(pDX, IDC_EDIT2, m_strLinkKey);
  642.     DDX_CBIndex(pDX, IDC_COMBO1, m_shape);
  643.     DDX_Control(pDX, IDC_EDIT1, m_editDescription);
  644.     DDX_Control(pDX, IDOK, m_btnOK);
  645.     //}}AFX_DATA_MAP
  646. }
  647.  
  648.  
  649. BEGIN_MESSAGE_MAP(CAddNodeDlg, CDialog)
  650.     //{{AFX_MSG_MAP(CAddNodeDlg)
  651.     ON_EN_CHANGE(IDC_EDIT1, OnChange)
  652.     //}}AFX_MSG_MAP
  653. END_MESSAGE_MAP()
  654.  
  655. void CAddNodeDlg::OnChange()
  656. {
  657.     if (m_btnOK.m_hWnd)
  658.         m_btnOK.EnableWindow(m_editDescription.GetWindowTextLength() > 0);
  659. }
  660.  
  661. //////////////////////////////////////////////////////////////////////////////
  662. // CServerItem construction
  663.  
  664. CServerItem::CServerItem(CServerDoc* pServerDoc, CServerNode* pServerNode)
  665.     : COleServerItem(pServerDoc, TRUE)
  666. {
  667.     // need to attach this server item to the node in the document
  668.     ASSERT_VALID(pServerNode);
  669.     m_pServerNode = pServerNode;
  670.     pServerNode->m_pServerItem = this;
  671.     pServerNode->UpdateItemName();
  672.  
  673.     // support CF_TEXT format
  674.     GetDataSource()->DelayRenderFileData(CF_TEXT);
  675. }
  676.  
  677. CServerItem::~CServerItem()
  678. {
  679.     if (m_pServerNode != NULL)
  680.     {
  681.         m_pServerNode->m_pServerItem = NULL;
  682.         m_pServerNode->m_strLinkKey = GetItemName();
  683.         m_pServerNode->UpdateItemName();
  684.     }
  685. }
  686.  
  687. //////////////////////////////////////////////////////////////////////////////
  688. // CServerItem verb handling
  689.  
  690. void CServerItem::OnOpen()
  691. {
  692.     if (IsLinkedItem() && m_pServerNode != NULL)
  693.     {
  694.         // for linked items, try to select this node in the document
  695.         CServerDoc* pDoc = GetDocument();
  696.         ASSERT(pDoc != NULL);
  697.         POSITION pos = pDoc->GetFirstViewPosition();
  698.         ASSERT(pos != NULL);
  699.         CServerView* pView = (CServerView*)pDoc->GetNextView(pos);
  700.         ASSERT_KINDOF(CServerView, pView);
  701.  
  702.         pView->SetSelection(m_pServerNode);
  703.         pView->ScrollToItem(m_pServerNode, TRUE);
  704.     }
  705.     COleServerItem::OnOpen();
  706. }
  707.  
  708. /////////////////////////////////////////////////////////////////////////////
  709. // CServerItem drawing
  710.  
  711. BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
  712. {
  713.     if (dwDrawAspect != DVASPECT_CONTENT)
  714.         return COleServerItem::OnGetExtent(dwDrawAspect, rSize);
  715.  
  716.     // determine extent based on screen dc
  717.     rSize = CSize(0, 0);
  718.     if (m_pServerNode != NULL)
  719.     {
  720.         CClientDC dc(NULL);
  721.         dc.SetMapMode(MM_ANISOTROPIC);
  722.         CServerDoc* pDoc = GetDocument();
  723.         ASSERT_VALID(pDoc);
  724.         CPoint ptStart(CX_MARGIN, CY_MARGIN);
  725.         pDoc->CalcBounding(&dc, m_pServerNode, ptStart, rSize);
  726.         rSize.cx += CX_MARGIN;
  727.         dc.LPtoHIMETRIC(&rSize); // convert pixels to HIMETRIC
  728.     }
  729.     return TRUE;
  730. }
  731.  
  732. BOOL CServerItem::OnDraw(CDC* pDC, CSize& rSize)
  733. {
  734.     if (m_pServerNode != NULL)
  735.     {
  736.         // determine extent of this item in the document
  737.         CServerDoc* pDoc = GetDocument();
  738.         ASSERT_VALID(pDoc);
  739.         rSize = CSize(0, 0);
  740.         CPoint ptStart(CX_MARGIN, CY_MARGIN);
  741.         pDoc->CalcBounding(pDC, m_pServerNode, ptStart, rSize);
  742.         rSize.cx += CX_MARGIN;
  743.  
  744.         // prepare to draw and remember the extent in himetric units
  745.         pDC->SetWindowOrg(0, 0);
  746.         pDC->SetWindowExt(rSize);
  747.         pDC->SetViewportExt(rSize);  // Note: only affects the m_hAttribDC
  748.  
  749.         pDC->LPtoHIMETRIC(&rSize);   // convert pixels to HIMETRIC
  750.  
  751.         // CServerDoc::DrawTree selects and releases font automatically
  752.         pDoc->DrawTree(pDC, ptStart, NULL, m_pServerNode) != -1;
  753.     }
  754.     return TRUE;
  755. }
  756.  
  757. /////////////////////////////////////////////////////////////////////////////
  758. // CServerItem clipboard handling
  759.  
  760. void CServerItem::Serialize(CArchive& ar)
  761. {
  762.     // serialize font info from document (so it looks like a document)
  763.     CServerDoc* pDoc = GetDocument();
  764.     ASSERT_VALID(pDoc);
  765.     pDoc->SerializeFontInfo(ar);
  766.  
  767.     // serialize node info
  768.     ASSERT_VALID(m_pServerNode);
  769.     m_pServerNode->Serialize(ar);
  770. }
  771.  
  772. BOOL CServerItem::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
  773. {
  774.     ASSERT(lpFormatEtc != NULL);
  775.     if (lpFormatEtc->cfFormat != CF_TEXT)
  776.         return COleServerItem::OnRenderFileData(lpFormatEtc, pFile);
  777.  
  778.     BOOL bResult = FALSE;
  779.     if (m_pServerNode != NULL)
  780.     {
  781.         TRY
  782.         {
  783.             // save as text
  784.             CArchive ar(pFile, CArchive::store);
  785.             m_pServerNode->SaveAsText(ar, 0);
  786.             ar << (BYTE)'\0';   // terminate with NUL character
  787.             bResult = TRUE;
  788.         }
  789.         END_TRY
  790.     }
  791.     return bResult;
  792. }
  793.  
  794. // OnGetClipboardData is used by CopyToClipboard and DoDragDrop
  795. COleDataSource* CServerItem::OnGetClipboardData(BOOL bIncludeLink,
  796.     LPPOINT pptOffset, LPSIZE pSize)
  797. {
  798.     ASSERT_VALID(this);
  799.  
  800.     if (m_pServerNode == NULL)
  801.         return NULL;
  802.  
  803.     COleDataSource* pDataSource = new COleDataSource;
  804.     TRY
  805.     {
  806.         GetNativeClipboardData(pDataSource);
  807.         GetClipboardData(pDataSource, bIncludeLink, pptOffset, pSize);
  808.     }
  809.     CATCH_ALL(e)
  810.     {
  811.         delete pDataSource;
  812.         THROW_LAST();
  813.     }
  814.     END_CATCH_ALL
  815.  
  816.     ASSERT_VALID(pDataSource);
  817.     return pDataSource;
  818. }
  819.  
  820. void CServerItem::GetNativeClipboardData(COleDataSource *pDataSource)
  821. {
  822.     ASSERT_VALID(this);
  823.     ASSERT(CServerDoc::m_cfPrivate != NULL);
  824.  
  825.     // Create a shared file and associate a CArchive with it
  826.     CSharedFile file;
  827.     CArchive ar(&file,CArchive::store);
  828.  
  829.     // Serialize selected objects to the archive
  830.     m_pServerNode->Serialize(ar);
  831.     ar.Close();
  832.  
  833.     // put on local format instead of or in addation to
  834.     pDataSource->CacheGlobalData(CServerDoc::m_cfPrivate,file.Detach());
  835. }
  836.  
  837. /////////////////////////////////////////////////////////////////////////////
  838.